package org.dev.hi.hiui.item

import android.content.Context
import android.util.SparseArray
import android.util.SparseIntArray
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.*
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import java.lang.RuntimeException
import java.lang.ref.WeakReference
import java.lang.reflect.ParameterizedType
import java.util.ArrayList

/**
 * Author WenPing
 * CreateTime 2021/4/18.
 * Description:创建HiAdapter实现列表功能的填充
 */
class HiAdapter(context: Context) : Adapter<ViewHolder>() {

    private var recyclerViewRef: WeakReference<RecyclerView>? = null

//    private var mContext: Context = context

    private var mInflater = LayoutInflater.from(context)

    /**
     * kotlin 中 out代表java中的 super
     * out 相当于 java 中的<T extends Type>
     */
    private var dataSet = ArrayList<HiDataItem<*, out ViewHolder>>()

    private val typePositions = SparseIntArray()

    /**
     * 列表的头部
     */
    private var headers = SparseArray<View>()

    private var footers = SparseArray<View>()

    private var BASE_ITEM_TYPE_HEADER = 1000000

    private var BASE_ITEM_TYPE_FOOTER = 2000000

    /**
     * 添加头部
     */
    fun addHeaderView(view: View) {
        if (headers.indexOfValue(view) < 0) {
            headers.put(BASE_ITEM_TYPE_HEADER++, view)
            //这个header是加在header列表的最后一个，所以用header.size-1
            notifyItemInserted(headers.size() - 1)
        }
    }

    /**
     * 添加footer
     */
    fun addFooterView(view: View) {
        if (footers.indexOfValue(view) < 0) {
            footers.put(BASE_ITEM_TYPE_FOOTER++, view)
            notifyItemInserted(itemCount)
        }
    }

    /**
     * 移除头部
     */
    fun removeHeaderView(view: View) {
        val indexOfValue = headers.indexOfValue(view)
        if (indexOfValue >= 0) {
            headers.removeAt(indexOfValue)
            notifyItemRemoved(indexOfValue)
        }
    }

    /**
     * 移除footer
     */
    fun removeFooterView(view: View) {
        val indexOfValue = footers.indexOfValue(view)
        if (indexOfValue >= 0) {
            //移除footers中对应的footers
            footers.removeAt(indexOfValue)
            //footer所在的真实位置
            notifyItemRemoved(indexOfValue + getHeaderSize() + getOriginalItemSize())
        }
    }

    /**
     * 返回不包括header和footer的列表数据
     */
    private fun getOriginalItemSize(): Int = dataSet.size

    /**
     * 返回头部的数量
     */
    private fun getHeaderSize(): Int = headers.size()

    fun getFootSize(): Int = footers.size()

    //给对应序号添加item
    fun addItemAt(
        index: Int,
        hiDataItem: HiDataItem<*, out ViewHolder>,
        notify: Boolean
    ) {
        if (index >= 0) {
            dataSet.add(index, hiDataItem)
        } else {
            dataSet.add(hiDataItem)
        }

        val notifyPosition = if (index >= 0) index else dataSet.size - 1
        if (notify) notifyItemInserted(index)
        //设置当前的适配器
        hiDataItem.setAdapter(this)
    }

    /**
     * 往集合尾部添加items集合
     */
    fun additemsAt(
        items: List<HiDataItem<*, out ViewHolder>>,
        notify: Boolean
    ) {
        val start = dataSet.size
        items.forEach { item ->
            dataSet.add(item)
            item.setAdapter(this)
        }
        /**
         * params:开始的序号和添加的集合是size
         */
        if (notify) notifyItemRangeInserted(start, items.size)
    }

    /**
     * 添加数据到适配器
     * 刷新列表通过调用当前的序号来指定刷新
     */
    fun addItems(items: List<HiDataItem<*, out RecyclerView.ViewHolder>>, notify: Boolean) {
        val start: Int = dataSet.size

        for (item in items) {
            dataSet.add(item)
            item.setAdapter(this)
        }
        if (notify) {
            notifyItemRangeInserted(start, items.size)
        }
    }

    fun removeItemAt(index: Int): HiDataItem<*, out ViewHolder>? {
        if (index >= 0 && index < dataSet.size) {
            val removeItem = dataSet.removeAt(index)
            notifyItemRemoved(index)
            return removeItem
        } else return null
    }

    /**
     * 移除指定的item
     */
    fun removeItem(hiDataItem: HiDataItem<*, out ViewHolder>) {
        val indexOf = dataSet.indexOf(hiDataItem)
        removeItemAt(indexOf)
    }

    /**
     * 指定刷新 某个item的数据
     */
    fun refreshItem(hiDataItem: HiDataItem<*, out ViewHolder>) {
        val index = dataSet.indexOf(hiDataItem)
        notifyItemChanged(index)
    }

    override fun getItemViewType(position: Int): Int {
        if (isHeaderPosition(position)) {
            return headers.keyAt(position)
        }

        if (isFootPosition(position)) {
            val footPosition = position - getHeaderSize() - getOriginalItemSize()
            return footers.keyAt(footPosition)
        }

        val itemPosition = position - getHeaderSize()
        val hiDataItem = dataSet[itemPosition]
        val type = hiDataItem.javaClass.hashCode()
        typePositions.put(type, position)
        return type
    }

    private fun isFootPosition(position: Int): Boolean =
        position >= getHeaderSize() + getOriginalItemSize()

    private fun isHeaderPosition(position: Int): Boolean = position < headers.size()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        if (headers.indexOfKey(viewType) >= 0) {
            val view = headers[viewType]
            return object : RecyclerView.ViewHolder(view) {}
        }
        if (footers.indexOfKey(viewType) >= 0) {
            val view = footers[viewType]
            return object : RecyclerView.ViewHolder(view) {}
        }

        /*
         * 对dataSet进行处理
         */
        val position = typePositions.get(viewType)
        val dataItem = dataSet.get(position)
        //让具体的派生类去实现
        var vh = dataItem.onCreateViewHolder(parent)
        if (vh != null) return vh

        var view: View? = dataItem.getItemView(parent)
        if (view == null) {
            var layoutRes = dataItem.getItemLayoutRes()
            if (layoutRes < 0) {
                throw RuntimeException("dataItem:" + dataItem.javaClass.name + " must override getItemView or getItemLayoutRes")
            }
            view = mInflater.inflate(layoutRes, parent, false)
        }
        return createViewHolderInternal(dataItem.javaClass, view!!)
    }

    private fun createViewHolderInternal(
        javaClass: Class<HiDataItem<*, out RecyclerView.ViewHolder>>,
        view: View
    ): RecyclerView.ViewHolder {
        val superClass = javaClass.genericSuperclass
        if (superClass is ParameterizedType) {

            val arguments = superClass.actualTypeArguments
            /**
             * 判断是不是RecyclerView的子类
             * 并创建对应的实例
             */
            for (argument in arguments) {
                if (argument is Class<*> && ViewHolder::class.java.isAssignableFrom(argument)) {
                    try {
                        // 调用recycler.ViewHolder的构造方法 传入一个参数，参数是 ietm的资源布局对应的View
                        return argument.getConstructor(View::class.java)
                            .newInstance(view) as ViewHolder
                    } catch (e: Throwable) {
                        e.printStackTrace()
                    }
                }
            }
        }
        return object : HiViewHolder(view) {}
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        if (isHeaderPosition(position) || isFootPosition(position)) return

        val itemPositon = position - getHeaderSize()
        val dataItem = getItem(itemPositon)
        dataItem?.onBindData(holder, itemPositon)
    }

    /**
     * 根据当前itemPosition去获取对应集合中元素
     */
    fun getItem(position: Int): HiDataItem<*, RecyclerView.ViewHolder>? {
        if (position < 0 || position >= dataSet.size)
            return null
        //进行一次强转
        return dataSet[position] as HiDataItem<*, RecyclerView.ViewHolder>
    }

    /**
     * 获得所有的item的数量
     * */
    override fun getItemCount(): Int = dataSet.size + footers.size() + headers.size()

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        recyclerViewRef = WeakReference(recyclerView)
        /**
         * 为列表上的item 适配王哥布局
         */
        val layoutManager = recyclerView.layoutManager
        if (layoutManager is GridLayoutManager) {
            val spanCount = layoutManager.spanCount
            layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
                override fun getSpanSize(position: Int): Int {
                    if (isHeaderPosition(position) || isFootPosition(position)) return spanCount
                    val itemPosition = position - getHeaderSize()
                    if (itemPosition < getOriginalItemSize()) {
                        val item = getItem(itemPosition)
                        if (item != null) {
                            val spanSize = item.getSpanSize()
                            return if (spanSize <= 0) spanCount else spanSize
                        }
                    }
                    return spanCount
                }
            }
        }
    }

    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        super.onDetachedFromRecyclerView(recyclerView)
        //移除 recyclerViewRef的引用
        recyclerViewRef?.clear()
    }

    open fun getAttachRecyclerView(): RecyclerView? = recyclerViewRef?.get()

    override fun onViewAttachedToWindow(holder: ViewHolder) {
        val attachRecyclerView = getAttachRecyclerView()
        if (attachRecyclerView != null) {
            //瀑布流式占比适配
            val position = attachRecyclerView.getChildAdapterPosition(holder.itemView)
            val isHeaderFooter = isHeaderPosition(position) || isFootPosition(position)
            val itemPosition = position - getHeaderSize()
            val hiDataItem = getItem(itemPosition) ?: return

            val layoutParams = holder.itemView.layoutParams
            if (layoutParams != null && layoutParams is StaggeredGridLayoutManager.LayoutParams) {
                val manager = attachRecyclerView.layoutManager as StaggeredGridLayoutManager?
                if (isHeaderFooter) {
                    layoutParams.isFullSpan = true
                    return
                } else {
                    val spanSize = hiDataItem.getSpanSize()
                    if (spanSize == manager!!.spanCount) {
                        layoutParams.isFullSpan = true
                    }
                }
            }
            hiDataItem.onViewAttachedToWindow(holder)
        }
    }

    override fun onViewDetachedFromWindow(holder: ViewHolder) {
        val position = holder.adapterPosition
        if (isHeaderPosition(position) || isFootPosition(position)) return

        val itemPosition = position - getHeaderSize()
        val dataItem = getItem(itemPosition) ?: return
        dataItem.onViewDetachedFromWindow(holder)
    }

    fun clearItems() {
        dataSet.clear()
        notifyDataSetChanged()
    }

}